package flowdroid.scan;

import cli.ConfigManager;
import db.DatabaseManager;
import flowdroid.MyFlowConfigManager;
import soot.Scene;
import soot.jimple.infoflow.android.SetupApplication;
import tuple.TupleManager;

import java.io.File;

import static util.Constant.getApkNameFromApkFilepath;

public class ScanPhase {

    /**
     * Scans methods in the given APK file, constructs a call graph (actually load methods by this action),
     * and marks methods using the provided MethodChecker.
     *
     * @param apkFileLocation    The location of the APK file to be analyzed.
     * @param configManager     The ConfigManager instance to manage configurations. AndroidJarPlatform and other configurations are used.
     * @param manager            The TupleManager instance to manage tuples.
     * @param marker             The MethodChecker instance to mark methods.
     * @return The SetupApplication instance used for the analysis.
     * @throws Exception If an error occurs during the analysis.
     */
    public static SetupApplication scanMethods(String apkFileLocation, ConfigManager configManager,
                                               TupleManager manager, MethodChecker marker)
            throws Exception {
        String androidJarPlatform=configManager.androidJarPlatform;
        String sourcesAndSinksPath=configManager.sourcesAndSinksPath;

        long startTime = System.currentTimeMillis();

        // 1. configure the Soot/FlowDroid environment & load methods by constructing a call graph
        String classpath = Scene.v().getAndroidJarPath(androidJarPlatform, apkFileLocation);
        SetupApplication app = new SetupApplication(new File(androidJarPlatform), new File(apkFileLocation));
        MyFlowConfigManager.resetEnvironment();
        MyFlowConfigManager flowConfigManager = new MyFlowConfigManager(app);
        boolean openReconstruction = false;
        flowConfigManager.configureAll(apkFileLocation, androidJarPlatform, classpath, openReconstruction,configManager);
        Scene.v().loadBasicClasses();
        app.constructCallgraph();
        manager.prepareScan();

        // [KEY ACTION] 2. scan methods and mark them
//        marker.processManifest(apkFileLocation,manager);

        marker.markMethods(manager,configManager.recordScanLog);

        // record time
        long endTime = System.currentTimeMillis();
        double duration = (endTime - startTime) / 60000.0; // Convert to minutes
        try{
            DatabaseManager.insertDataFlowTime(getApkNameFromApkFilepath(apkFileLocation), "SCAN", duration);
        }
        catch (Exception e) {
            e.printStackTrace();
            System.err.println("A DB error occurred. In file: ScanPhase.java, and caused by invoking insertDataFlowTime(...)");
        }
        return app;
    }
}
